home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / pascal / tgraph.com / TGRAPH.DOC < prev    next >
Encoding:
Text File  |  1991-01-04  |  23.4 KB  |  570 lines

  1. ------------------------------------------------------------------------------
  2.                            TGRAPH  Release 3.1
  3. ------------------------------------------------------------------------------
  4.  
  5.  
  6. TGRAPH -- Full access to the Tandy 1000's extra graphics modes with 
  7.           TurboPascal versions 4.0, 5.0, 5.5, or 6.0.
  8.  
  9.  
  10. Why the TGRAPH package?
  11.         
  12.         The Tandy 1000 has greater graphics capabilities than the other 
  13. members of the IBM PC compatible family.  It alone supports 160x200 
  14. 16-color, 320x200 16-color, and 640x200 4-color graphics schemes.  BIOS 
  15. calls those three extra video modes 8, 9, and 10 respectively. 
  16.  
  17.         Traditionally those extra modes have been accessible only from 
  18. one high-level language: the interpreted GW-BASIC supplied with the 
  19. computer.  BASIC calls those modes SCREEN 3, 5, and 6.  
  20.  
  21.         TurboPascal, as it comes off the shelf, is blind to the fancy 
  22. color and graphics tricks the Tandy 1000 can perform.  These routines 
  23. in TGRAPH offer programmers easy access to Video Mode 9.  That's the 
  24. 16-color, 320x200 screen which can be dazzling in a program.  (Much of 
  25. this material also will work in modes 8 and 10, but it has been 
  26. developed and tested primarily for mode 9.)  
  27.  
  28.  
  29. You MUST protect the screen memory area first:
  30.  
  31.         Though we'll discuss protecting screen memory in detail later,
  32. in TP 4.0 or later just placing a compiler directive limiting the stack 
  33. and heap sizes at the top of your program will probably get you going 
  34. through all your early projects with TGRAPH.  Just do this at the top 
  35. of your program for now:
  36.         
  37.                    {$M 8000,0,0} 
  38.  
  39.         That will set a smallish stack with no heap.  If your program 
  40. bombs, locks, or has distorted graphics images you'll need to consider 
  41. exactly what's happening up high in memory after reading the later 
  42. discussion.  And especially you'll need to study that if you are 
  43. allocating heap memory. 
  44.  
  45.  
  46. Will TGRAPH work on an EGA?
  47.  
  48.         Nope.  EGA screen memory is organized quite differently.  Even 
  49. though there are similar appearing video capabilities with an EGA, the 
  50. video modes are numbered dissimilarly and work differently.  That 'T' 
  51. in TGRAPH stands for Tandy 1000. 
  52.  
  53.  
  54. How to incorporate TGRAPH:
  55.  
  56.         With TurboPascal versions 4.0 or later, just specify TGRAPH40, 
  57. TGRAPH50, TGRAPH55, or TGRAPH60 in a USES statement depending on which 
  58. version of TurboPascal you're using.  The TGRAPHxx.TPU file of this 
  59. archive must be accessible to TurboPascal during compilation -- show 
  60. the appropriate path in Options/Directories/Units.  
  61.  
  62.  
  63. Here are TGRAPH's procedures and functions:
  64.  
  65. [Any reference to a color in these routines will accept integers 0 - 15 
  66. or TurboPascal's pre-defined constants such as Red, Blue, or LightCyan.  
  67. Those constants are defined in the Crt Unit.]  
  68.  
  69.     Plot
  70.         Syntax: Plot (X,Y,Color);
  71.  
  72.         Places a single pixel at the X, Y location in the specified 
  73.         Color.
  74.  
  75.     Draw
  76.         Syntax: Draw (X1,Y1,X2,Y2,Color);
  77.  
  78.         Draws a line from the X1, Y1 starting point to X2, Y2 in the 
  79.         specified Color.
  80.  
  81.     Circle
  82.         Syntax: Circle (X,Y,Radius,Color);
  83.  
  84.         Draws a circle in the specified Color with its center at X, Y 
  85.         using the specified Radius.
  86.  
  87.     GetPic
  88.         Syntax: GetPic (Buffer,X1,Y1,X2,Y2);
  89.  
  90.         Copies the contents of a rectangular area defined by X1, Y1, 
  91.         X2, and Y2 into the variable Buffer.
  92.  
  93.         The Buffer should be defined as an array of byte.  Its minimum 
  94.         size can be calculated as follows:
  95.  
  96.               when Width  := abs(x1-x2)+1
  97.                and Height := abs(y1-y2)+1
  98.  
  99.               then BufferSize :=  4+((Width +1) div 2)*Height
  100.         
  101.     PutPic
  102.         Syntax: PutPic (Buffer,X,Y);
  103.         
  104.         Copies the contents of the variable Buffer onto a rectangular 
  105.         area of the screen.  X and Y define the upper left-hand corner 
  106.         of the picture area.  (Caution to TP3 users: that language 
  107.         used the lower left-hand corner.)  Buffer is a variable defined 
  108.         as an array of byte in which a picture has been previously 
  109.         stored by GetPic. 
  110.  
  111.     PutPix
  112.         Syntax: PutPix (Buffer,X,Y);
  113.  
  114.         An XOR version of PutPic, this can be is useful for two sorts 
  115.         of special effects.  You can erase an image by using PutPix to 
  116.         place a second copy at the same location already placed on the 
  117.         screen by PutPic.  That can be useful for animation effects.  
  118.  
  119.         And you can blend or appear to overlay two images with each 
  120.         other.  It's easier to see how this works with some 
  121.         experimentation than to explain.  
  122.  
  123.         A Brown pixel on the screen being XORed by a Cyan pixel in the 
  124.         PutPix image will result in a Magenta pixel being displayed:
  125.  
  126.                 Brown    = 0110 binary  = 6 decimal   
  127.                 Cyan     = 0011 binary  = 3 decimal
  128.                         XOR 
  129.                 Magenta  = 0101 binary  = 5 decimal  
  130.  
  131.     PutDelay
  132.         Syntax: PutDelay (Buffer,X,Y,Speed);
  133.  
  134.         Similar to PutPic except the speed of display is controlled by 
  135.         the integer Speed which may be between 1 and 9999.  1 will put 
  136.         the picture onto the screen just about as fast as the plain 
  137.         PutPic.  A value of 50 will fill a screen in about 6 seconds 
  138.         on a 4.7 mHz 8088 machine, and a value of 9999 takes forever.  
  139.         Be careful, a value of 0 is the same as 9999. 
  140.  
  141.     SetCrtMode
  142.         Syntax: SetCrtMode (Mode,ClearFlag);
  143.  
  144.         Sets video mode to that specified by the integer Mode and clears 
  145.         or does not clear the screen according to the boolean ClearFlag 
  146.         being either 'True' or 'False'.  If the ClearFlag is set false 
  147.         and the previous screen is incompatible with the requested 
  148.         mode, clearing will occur anyway. 
  149.  
  150.         The applicable modes are:
  151.  
  152.          0:  Text     40x25 black and white
  153.          1:  Text     40x25 color
  154.          2:  Text     80x25 black and white
  155.          3:  Text     80x25 color
  156.          4:  Graphic  320x200 4-color graphics
  157.          5:  Graphic  320x200 "gray" graphics on composite monitor
  158.          6:  Graphic  640x200 "high resolution" black and white graphics
  159.          --   -----   
  160.          8:  Graphic  160x200 16-color graphics
  161.          9:  Graphic  320x200 16-color graphics
  162.         10:  Graphic  640x200 4-color graphics
  163.  
  164.     GetCrtMode
  165.         Syntax: GetCrtMode
  166.  
  167.         Integer function returns the present video mode.  A tidy use 
  168.         would be to call GetCrtMode upon entering the program, enter a 
  169.         graphics mode to do other processing, and then use SetCrtMode 
  170.         to return the mode to what it was before exiting.  
  171.  
  172.         Example: StartingMode := GetCrtMode;
  173.  
  174.     GraphBorder
  175.         Syntax: GraphBorder (Color);
  176.  
  177.         Sets the screen border to the specified Color.
  178.  
  179.     GraphBackground
  180.         Syntax: GraphBackground (Color);
  181.         
  182.         Sets the entire screen, interior and border, to the specified
  183.         Color.
  184.         
  185.     BorderBack
  186.         Syntax: BorderBack (BorderColor,InteriorColor);
  187.         
  188.         Sets the interior and border of the screen to the specified
  189.         colors.
  190.         
  191.     ClearScreen
  192.         Syntax: ClearScreen;
  193.  
  194.         Clears the screen of all markings except the previously 
  195.         established border and interior colors.
  196.                            
  197.     FillScreen
  198.         Syntax: FillScreen (Color);
  199.  
  200.         This procedure differs from GraphBackground in that FillScreen 
  201.         always leaves the border black.  FillScreen colors the interior 
  202.         of the screen with the specified Color. 
  203.  
  204.     Recolor
  205.         Syntax: Recolor (Color1,Color2);
  206.  
  207.         Changes all instances of integer Color1 presently on screen to
  208.         Color2.
  209.  
  210.     FillWindow
  211.         Syntax: FillWindow (X1,Y1,X2,Y2,Color);
  212.  
  213.         Fills a rectangular area of the screen defined by the integer 
  214.         coordinates with integer color. 
  215.  
  216.     CheckForTandy
  217.         Syntax: CheckForTandy
  218.  
  219.         Boolean function searches BIOS-ROM for 'andy' or 'ANDY'.  Used 
  220.         for attempting to ascertain if there is a Tandy copyright which 
  221.         would give some assurance that a program is about to be run on 
  222.         a Tandy 1000.  Obviously, Tandy 1200s, 2000s, 3000s, and 4000s 
  223.         will also contain that string.  Returns 'True' if string found. 
  224.  
  225.         Example:  If CheckForTandy = true then ...
  226.  
  227.     Paint
  228.         Syntax: Paint (X,Y,FillColor,BorderColor)
  229.  
  230.         Starting at the X, Y location fills an area delimited by 
  231.         BorderColor with FillColor.
  232.  
  233.  
  234. Identifying a Tandy 1000
  235.  
  236.         In my own Tandy 1000 graphics programming I've always thought 
  237. it important to make certain the user really is running the program on 
  238. a Tandy 1000.  Any Video Mode 9 program sure is going to be weird on 
  239. the rest of the IBM PC compatibles.  It won't break anything, but 
  240. neither will the graphics screens display.
  241.  
  242.         Tandy has previously been awfully close-mouthed about any 
  243. unique signature byte any place in ROM so my identification schemes 
  244. have been built on several checks.  
  245.         
  246.         First I use the CheckForTandy function above.
  247.  
  248.         Next, the byte in BIOS ROM at Mem[$F000:$FFFE] can help 
  249. identify the machine.  An $FD there positively identifies an IBM PCjr.  
  250. An $FF indicates an IBM PC or compatible -- the Tandy 1000 will have 
  251. $FF.  (And Tandy 2000s will be weeded out by a $00.  Perhaps 3000s and 
  252. 4000s are not $FF, I haven't been able to test.  An IBM PC XT has $FE 
  253. and an IBM PC AT has $FC there.  If all their clones follow that 
  254. scheme, you will rule them out easily.) 
  255.  
  256.         If both those tests pass, then I have looked at the DOS 
  257. equipment list for total memory available to see if it reports 16K 
  258. less than you'd expect.  That is, has the 16K taken by the screen 
  259. memory been subtracted from 128, 256, 384, 512, or 640K.  Specifically, 
  260. see if the byte at Mem[$0040:$0013] is either $70 or $F0.  
  261.  
  262.         A Tandy 1000 TL though may be configured with up to 64k used 
  263. for multiple pages of video memory, and that same machine might have 
  264. add-on dedicated video memory giving 128k for video memory.  It, and 
  265. any later members of the Tandy 1000 family using the same scheme, will 
  266. slip through the above described sequence. 
  267.  
  268.         In my own Tandy 1000 graphics programming, I have previously 
  269. done the above checking sequence, but then, if I can't positively 
  270. identify a Tandy 1000, have given the user a chance to insist that the 
  271. machine is, in fact, a Tandy 1000. 
  272.  
  273.         Bryan Headley, a Tandy staffer providing vendor development 
  274. support on CompuServe, in May 1989, suggested another check sequence, 
  275. presumably speaking officially for Tandy though they certainly had been 
  276. tight about it previously. 
  277.  
  278.         He says first check for EGA, VGA, Hercules, etc.  If these all 
  279. fail then assume this is a CGA.  He doesn't say how to do that check, 
  280. and the only method I know of would be to use TP's DetectGraph function 
  281. from its Graph unit.  I have no idea what it is really looking for. 
  282.  
  283.         Having ruled out the other sorts of video displays, he says 
  284. next check that Mem[$F000:$FEEE]=$FF -- that's the Machine ID byte 
  285. we've discussed earlier. 
  286.  
  287.         And finally then check for Mem[$F000:$C000]=$21 which is a 
  288. unique signature byte for Tandy 1000s if the machine is first 
  289. determined to be a CGA and the Machine ID is $FF.
  290.  
  291.         My most recent programming goes in for overkill by doing all of 
  292. these things with a Tandy1000 boolean function like this: 
  293.  
  294.      Function Tandy1000 : boolean;
  295.      begin
  296.  
  297.      Tandy1000 := true;    {Initialize the function as true.  Both
  298.                             the check sequences below exit if 
  299.                             successful and the function gets defined
  300.                             false only if they fail.}
  301.  
  302.      If     (Mem[$F000:$FFFE] = $FF)
  303.         and (CheckForTandy)
  304.         and (((Mem[$0040:$0013]=$70) or (Mem[$0040:$0013]=$F0)))
  305.      then exit
  306.  
  307.      Else begin
  308.      DetectGraph(GrDriver,GrMode);
  309.      If     (GrDriver=CGA) 
  310.         and (Mem[$F000:$FEEE] = $FF)
  311.         and (Mem[$F000:$C000] = $21)
  312.      then exit;
  313.      end;
  314.  
  315.      Tandy1000:=false;
  316.      end;
  317.  
  318.  
  319. More on protecting screen memory:
  320.  
  321.         The usual Tandy 1000, in any of the 'normal' video modes below 
  322. 9, uses the top 16K of installed RAM for screen memory.  That address 
  323. varies according to how much memory you have installed, but BIOS then 
  324. does a trick to call that address $B800 as the start of the screen 
  325. memory area regardless of how many memory chips are present. 
  326.  
  327.         When using video modes 9 or 10 you need 32K at the top of 
  328. RAM for screen memory.  BIOS is still going to address it as $B800, but 
  329. the true address will now be 32K below the top of installed RAM. 
  330.  
  331.         BIOS-ROM automatically protects the top 16K of the Tandy 1000
  332. from being overwritten by anything.  But there is no automatic
  333. protection for the next 16K when you are using one of the video modes
  334. needing a total of 32K.  You've got to do that yourself.  And if you
  335. don't do so, any program using Video Mode 9 may crash dead requiring 
  336. you to punch the Big Orange Button. 
  337.  
  338.         With TP3 it was especially tricky protecting that top 32k of 
  339. memory since that language version would generally attempt to build its 
  340. stack downward from the highest RAM location DOS told it was available.  
  341. That was right in the middle of our screen memory and every single 
  342. program got clobbered without some trickery.
  343.  
  344.         (This present incarnation of TGRAPH no longer supports TP3 
  345. though earlier versions did.  If you are using TP3 you'll want to write 
  346. me directly for a copy of an earlier TGRAPH version which includes the 
  347. necessary files.  dpg)
  348.  
  349.         TP4, TP5, TP55, and TP6 all default to beginning the stack 16k 
  350. above the top of the executable program.  In many situations that 
  351. would not be likely to damage the screen memory, but as a general rule 
  352. I'd urge you to declare a smaller stack.  That's what the {$M 
  353. 8000,0,0} compiler directive discussed much earlier did to set about 
  354. an 8k stack.  
  355.         
  356.         Then if you're using TP's heap for pointer structures you'll 
  357. need to limit it as precisely as possible.  The heap in these later 
  358. language versions by default will be started just above the stack and 
  359. will grow upwards to the maximum memory installed in the machine 
  360. possibly clobbering the screen memory.  
  361.  
  362.         Calculate your heap requirements carefully and specify as small 
  363. a HeapMax in the {$M directive as possible.
  364.  
  365.         These methods of limiting memory will probably succeed for most 
  366. of the computer environments your program will be run in.  Remember 
  367. though that DOS has no way of officially knowing that all the top 32K 
  368. is forbidden territory.  In a multi-tasking situation, screen memory 
  369. may get clobbered.  In a machine with limited total RAM, or with much 
  370. of RAM filled up by resident programs, screen memory may get clobbered 
  371. even with small stack and heap allocations.  
  372.  
  373.         Most of the time you'll be safe.  We're not talking about 
  374. physical damage to anything, just a program that locks up the system. 
  375.  
  376.         I've always thought it classy to have the program calculate how 
  377. much memory is available above it and, prior to setting Video Mode 9, 
  378. refuse to run if it finds that the additional screen memory will be 
  379. damaged by the program. 
  380.  
  381.         This AdequateMemory procedure is an approach I've used to doing
  382. that.  It uses DOS function $48, Allocate Memory, to request an
  383. impossibly large block of memory.  When DOS returns with an error, the
  384. actual amount of memory available is in BX expressed in paragraphs.
  385. You can check to see that it is at least 16384 bytes.  
  386.  
  387.      Procedure AdequateMemory ;
  388.      var Regs:registers;        {defined in the DOS unit}
  389.  
  390.      begin
  391.         Regs.ah := $48;         { $48 -- attempt to Allocate Memory   }
  392.         Regs.bx := $FFFF;       { at an impossibly high value.  Error }
  393.         MsDos(Regs);            { will return available memory in BX  }
  394.  
  395.         if (Regs.bx * 16.0) < 16384.0 then
  396.         begin
  397.            writeln('Sorry.  Insufficient graphics memory.');
  398.            writeln('You need ',16384 - (Regs.bx * 16),' bytes more.');
  399.            halt;
  400.         end;   { if Regs.bx }
  401.      end;      { AdequateMemory }
  402.  
  403.  
  404. Origins of TGRAPH:
  405.  
  406.         The TGRAPH routines except two have all been written in 
  407. assembly language by Joe Glockner who is primarily responsible for 
  408. developing the entire package.
  409.  
  410.         I, the author of this documentation, Don Phillip Gibson, had 
  411. written a MONOPOLY game which became immensely popular.  It used TP3's 
  412. standard CGA four-color graphics schemes.  Joe became entranced with 
  413. that game and was determined to get it adapted to his new Tandy 1000's 
  414. graphics capabilities.  At that time he knew zilch about TurboPascal 
  415. and absolutely nothing about assembly language.  But he knew he wanted 
  416. a sixteen-color MONOPOLY board! 
  417.  
  418.         Joe began constructing sixteen-color boards in GW-BASIC and 
  419. they looked great, but interpreted BASIC would never be acceptable 
  420. running that game.  He taught himself TurboPascal to tinker around with 
  421. the game source files some more.  
  422.  
  423.         William Harris, Cleveland, Ohio, in 1985 had written and made 
  424. available on CompuServe's BORPRO a group of TP3 procedures which made 
  425. access to video modes 9 and 10 possible.  He provided the necessary 
  426. capability with TP3 to protect an area of RAM for the additional screen 
  427. memory required, and to set the screen modes.  Using TurboPascal's 
  428. Intr() procedure, he constructed replacements for the usual Draw and 
  429. Plot type of necessities.  
  430.                          
  431.         I sent Joe a copy of Harris' graphics routines but patiently 
  432. tried to explain they simply would never do the job for the MONOPOLY 
  433. game without accompanying GetPic and PutPic routines.  I was getting a 
  434. little concerned about how I could get this fanatic off my game. 
  435.  
  436.         And the next thing I knew, Joe had taught himself assembly 
  437. language and had constructed beautiful GetPic and PutPic routines in 
  438. assembly language for my use.  All of this within four months time!  
  439. That's two completely different programming languages he learned to 
  440. accomplish it.  I was overwhelmed. 
  441.  
  442.         Joe didn't even stop there, but went ahead to develop the full 
  443. set of machine coded graphics procedures found in TGRAPH.  
  444.  
  445.         The Draw routine used for the TP3 version of TGRAPH was Joe's 
  446. machine coded one, but it misbehaved mysteriously with TP4 and William 
  447. Harris' TurboPascal procedure now replaces it.  It turned out to be 
  448. just as fast and small.
  449.  
  450.         The Paint procedure added with TGRAPH v3.0 began as a machine 
  451. coded routine in the 'Bluebook of Assembly Language Routines for the 
  452. IBM PC & XT' by Christopher L. Morgan, The Waite Group, 1984.  
  453.  
  454.         Joseph A. Albrecht of Belle Plain, Minnesota, another devotee 
  455. of Tandy 1000's graphics, adapted Morgan's Paint procedure to Video 
  456. Mode 9 and increased its speed tremendously so that it became a truly 
  457. usable tool.  It is with Albrecht's permission that I have adapted his 
  458. assembler code to be added to TGRAPH v3.0. 
  459.  
  460.         (Albrecht has distributed the GRAFIX package of routines which 
  461. interface especially nicely with QuickBASIC but are also usable via 
  462. Intr() calls from TurboPascal or any language which can call an 
  463. interrupt.  GRAFIX requires installation of a memory resident library.) 
  464.  
  465.  
  466. This Stuff is Public Domain:
  467.  
  468.         These routines are placed into public domain for the use of
  469. TurboPascal programmers working with the Tandy 1000.  Further 
  470. distribution is encouraged as long as it is done without charge for the 
  471. program material. 
  472.  
  473.  
  474. Original TGRAPH author:
  475.  
  476.                  Joe Glockner   
  477.                  915 Boone Drive
  478.                  Sherman, TX 75090
  479.  
  480. TGRAPH.DOC and on-going support by:
  481.  
  482.                  Don Phillip Gibson
  483.                  910 East 11th
  484.                  Winfield, KS 67156
  485.  
  486.                  CompuServe: 75725,1752
  487.                  GEnie: DGIBSON
  488.  
  489.  
  490. Contents of the TGRAPH package:
  491.  
  492.         TGRAPH40.TPU   -  The unit for use with TurboPascal 4.0
  493.         TGRAPH50.TPU   -  The unit for use with TurboPascal 5.0
  494.         TGRAPH55.TPU   -  The unit for use with TurboPascal 5.5          
  495.  
  496.         TGRAPH60.TPU   -  The unit for use with TurboPascal 6.0
  497.  
  498.         DEMO.PAS       -  Brief demonstration ready for compilation.
  499.  
  500.         TGRAPH.DOC     -  This file.
  501.  
  502.  
  503. Revisions:
  504.  
  505.         1.0     Original release, supported only TurboPascal v3.+  
  506.                 (August, 1987)
  507.  
  508.         2.0     Added the TPU support for TP4.  (December 18, 1987)
  509.  
  510.         2.1     Fixed a flaky bug in the Draw procedure which acted up
  511.                 only in TGRAPH40.TPU (new file dated Mar 27, 1988.)
  512.  
  513.         2.2     Added the TPU support for TP5.  (October 1, 1988)
  514.  
  515.         3.0     Added the Paint procedure and the TPU for TP55.  
  516.                 Documentation revised and all TP3 material removed from 
  517.                 the package.  (September 4, 1989) 
  518.         
  519.         3.1     Added the TPU support for TP6.  (January 4, 1991)
  520.  
  521.  
  522.          ----------------end-of-author's-documentation---------------
  523.  
  524.                          Software Library Information:
  525.  
  526.                     This disk copy provided as a service of
  527.  
  528.                            Public (software) Library
  529.  
  530.          We are not the authors of this program, nor are we associated
  531.          with the author in any way other than as a distributor of the
  532.          program in accordance with the author's terms of distribution.
  533.  
  534.          Please direct shareware payments and specific questions about
  535.          this program to the author of the program, whose name appears
  536.          elsewhere in  this documentation. If you have trouble getting
  537.          in touch with the author,  we will do whatever we can to help
  538.          you with your questions. All programs have been tested and do
  539.          run.  To report problems,  please use the form that is in the
  540.          file PROBLEM.DOC on many of our disks or in other written for-
  541.          mat with screen printouts, if possible.  PsL cannot debug pro-
  542.          programs over the telephone, though we can answer questions.
  543.  
  544.          Disks in the PsL are updated  monthly,  so if you did not get
  545.          this disk directly from the PsL, you should be aware that the
  546.          files in this set may no longer be the current versions. Also,
  547.          if you got this disk from another vendor and are having prob-
  548.          lems,  be aware that  some files may have become corrupted or
  549.          lost by that vendor. Get a current, working disk from PsL.
  550.  
  551.          For a copy of the latest monthly software library newsletter
  552.          and a list of the 3,000+ disks in the library, call or write
  553.  
  554.                            Public (software) Library
  555.                                P.O.Box 35705 - F
  556.                             Houston, TX 77235-5705
  557.  
  558.                                  Orders only:
  559.                                 1-800-2424-PSL
  560.                               MC/Visa/AmEx/Discover
  561.  
  562.                           Outside of U.S. or in Texas
  563.                           or for general information,
  564.                               Call 1-713-524-6394
  565.  
  566.                           PsL also has an outstanding
  567.                           catalog for the Macintosh.
  568.  
  569.  
  570.